package com.warrior.gatherclient.service.impl;

import com.warrior.gatherclient.grpc.Messages;
import com.warrior.gatherclient.service.GpuService;
import com.warrior.gatherclient.util.CommonUtil;
import com.warrior.gatherclient.service.SystemInfoService;
import com.warrior.gathercommon.constants.CommonStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import oshi.SystemInfo;
import oshi.hardware.GraphicsCard;

import java.util.List;

/**
 * @ClassName GpuServiceImpl.java
 * @Author xujian
 * @Description
 * @CreateTime 2020年12月29日 15:26:00
 */
@Slf4j
@Service
public class GpuServiceImpl implements GpuService {

    private final static String GPU_SPLIT_ONE = "\\|===============================\\+======================\\+======================\\|";

    private final static String GPU_SPLIT_TWO = "\\+-------------------------------\\+----------------------\\+----------------------\\+";

    private final static String GPU_SPLIT_BLANK = "                                                                               ";

    private final static String GPU_MIB = "MiB";

    @Autowired
    private SystemInfoService systemInfoService;

    @Override
    public String getServiceKey() {
        return CommonStatus.CONSTANT_GPU;
    }

    @Override
    public Messages.Builder execute() {
        String gpus = getGpuInfo();
        if (StringUtils.isEmpty(gpus)) {
            log.warn("========== 根据英伟达显卡命令采集gpu信息为空 =========");
            return null;
        }
        Messages.Builder messages = CommonUtil.initMessage(CommonStatus.CONSTANT_GPU);
        addGpuInfo(messages);

        String[] split = gpus.split(GPU_SPLIT_ONE);
        String[] gpusInfo = split[1].split(GPU_SPLIT_BLANK);
        // 分割多个gpu
        String[] gpuInfo = gpusInfo[0].split(GPU_SPLIT_TWO);
        for (int i = 0; i < gpuInfo.length - 1; i++) {
            String[] nameAndInfo = gpuInfo[i].split("\n");
            //只要第二块的数据
            String[] split1 = nameAndInfo[1].split("\\|")[1]
                    .split("\\s+");//去空格
            StringBuffer name = new StringBuffer();
            for (int j = 0; j < split1.length - 1; j++) {
                if (j > 1 && j != split1.length) {
                    name.append(split1[j] + " ");
                }
            }

            Messages.Metric.Builder builder = Messages.Metric.newBuilder();
            builder.setMetricName(CommonStatus.CONSTANT_GPU_UTILIZATION);
            String[] info = nameAndInfo[2].split("\\|")[2].split("\\s+");

            int useable = Integer.parseInt(info[3].split(GPU_MIB)[0]) - Integer.parseInt(info[1].split(GPU_MIB)[0]);
            Double usageRate = Integer.parseInt(info[1].split(GPU_MIB)[0]) * 100.00 / Integer.parseInt(info[3].split(GPU_MIB)[0]);
            builder.setMetricVaule(name + split1[1] + CommonStatus.CONSTANT_JOINTSTR + usageRate + "%");
            messages.addMetrics(builder);
        }
        return messages;
    }


    private void addGpuInfo(Messages.Builder messages){
        SystemInfo systemInfo = systemInfoService.getSystemInfo();
        List<GraphicsCard> graphicsCards = systemInfo.getHardware().getGraphicsCards();
        graphicsCards.forEach(item -> {
            Messages.Metric.Builder builder = Messages.Metric.newBuilder();
            builder.setMetricName(CommonStatus.CONSTANT_GPU_NAME);
            builder.setMetricVaule(item.getName());
            messages.addMetrics(builder);

            Messages.Metric.Builder vramBuilder = Messages.Metric.newBuilder();
            vramBuilder.setMetricName(CommonStatus.CONSTANT_GPU_VRAM);
            vramBuilder.setMetricVaule(CommonUtil.formatByte(item.getVRam()));
            messages.addMetrics(vramBuilder);
        });
    }

    private String getGpuInfo() {
        String[] shell = {"/bin/bash", "-c", "nvidia-smi"};
        String result = CommonUtil.executeScript("nvidia-smi.exe", shell);
        return result;
    }

}
